package com.twang.stock.strategy;


import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.twang.stock.config.StockMsgSender;
import com.twang.stock.dto.EmailMessage;
import com.twang.stock.entity.*;
import com.twang.stock.entity.ex.StockWarningEventEx;
import com.twang.stock.mapper.*;
import com.twang.stock.redis.RedisUtil;
import com.twang.stock.service.MinutesChengJIaoeService;
import com.twang.stock.service.jinyan.CommonService;
import com.twang.stock.threadPool.AsycTaskExecutorConfig;
import com.twang.stock.utils.date.HolidayCopy;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;


/**
 * 60天最大成交量update
 */
@Service
@Slf4j
public class Stock60MinutesUpdate {

    public static String WARN_KEY="WARN_MAX_VOL_ID";

    public static String StockWarningEvent_YU_JING = "StockWarningEvent_YU_JING_";
    @Autowired
    private RedisUtil redisUtil;
    @Resource
    private StockWarningEventMapper stockWarningEventMapper;

    @Resource
    private CompanyCodeInfoMapper companyCodeInfoMapper;

    @Resource
    private CompanyStockMinutesMapper companyStockMinutesMapper;

    @Resource
    private KaiPanLaZhangTingInfoMapper kaiPanLaZhangTingInfoMapper;


    @Autowired
    private CommonService commonService;

    @Resource
    private StockMsgSender stockMsgSender;

    @Resource
    private UserMapper userMapper;

    @Resource
    private AsycTaskExecutorConfig asycTaskExecutorConfig;

    @Resource
    private ZhangTingBanMapper zhangTingBanMapper;

    public volatile static  ConcurrentHashMap<String,BigDecimal> MAX_60_DAY_TRADE_VOL=new ConcurrentHashMap<>();

    /**
     * 手动更新
     * @throws InterruptedException
     */
    public void update() throws InterruptedException {
        List<CompanyCodeInfo> companyCodeInfos = companyCodeInfoMapper.selectAll();
        List<CompanyCodeInfo> companyCodeInfoList=Lists.newArrayList();
        for(int i=1;i<11;i++) {
            companyCodeInfoList.addAll(companyCodeInfos.subList(i - 1, i * 500));
            extracted(companyCodeInfos, companyCodeInfoList);
        }
        companyCodeInfoList.addAll(companyCodeInfos.subList(5000,companyCodeInfos.size()-1));
        extracted(companyCodeInfos, companyCodeInfoList);


    }

    /**
     * 手动执行预警
     */
    public void warn() throws InterruptedException {
        List<CompanyCodeInfo> companyCodeInfos = companyCodeInfoMapper.selectAll();
        List<CompanyCodeInfo> companyCodeInfoList=Lists.newArrayList();
        for(int i=1;i<11;i++) {
            companyCodeInfoList.addAll(companyCodeInfos.subList(i - 1, i * 500));
            CountDownLatch countDownLatch = new CountDownLatch(companyCodeInfoList.size());
            companyCodeInfoList.stream().forEach(item -> {
                asycTaskExecutorConfig.taskQueueExecutor().execute(() -> {
                    try{
                        CompanyStockMinutes companyStockMinutes= companyStockMinutesMapper.queryByCode(item.getCompanyCode());
                        if(null!=companyStockMinutes){
                            warnMax60Vol(companyStockMinutes);
                        }
                    }finally {
                        countDownLatch.countDown();
                        log.info("============> 60天最大成交量 warn completed name={}  left num={}",item.getShortName(),countDownLatch.getCount());
                    }
                });
            });
            countDownLatch.await();
        }
        companyCodeInfoList.addAll(companyCodeInfos.subList(5000,companyCodeInfos.size()-1));
        CountDownLatch countDownLatch = new CountDownLatch(companyCodeInfoList.size());
        companyCodeInfoList.stream().forEach(item -> {
            asycTaskExecutorConfig.taskQueueExecutor().execute(() -> {
                try{
                    warnMax60Vol(companyStockMinutesMapper.queryByCode(item.getCompanyCode()));
                }finally {
                    countDownLatch.countDown();
                    log.info("============> 60天最大成交量 warn completed name={}  left num={}",item.getShortName(),countDownLatch.getCount());
                }
            });
        });
        countDownLatch.await();
        log.info("============>  60天最大成交量 update End!");
    }

    /**
     *
     * @param companyCodeInfos
     * @param companyCodeInfoList
     * @throws InterruptedException
     */
    private void extracted(List<CompanyCodeInfo> companyCodeInfos, List<CompanyCodeInfo> companyCodeInfoList) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(companyCodeInfoList.size());
        companyCodeInfos.stream().forEach(item -> {
            asycTaskExecutorConfig.taskQueueExecutor().execute(() -> {
                try {
                    updateMaxVol(item.getCompanyCode());
                } finally {
                    countDownLatch.countDown();
                }
                // log.info(">>>>>>>>>>> 60天最大成交量update success code={} name={}", item.getCompanyCode(), item.getCompanyName());
            });
        });
        countDownLatch.await();
        companyCodeInfoList.clear();
    }


    /**
     * update 60日 Max trade vol
     * @param code
     */
    public void updateMaxVol(String code) {
        CompanyCodeInfo param = new CompanyCodeInfo();
        param.setCompanyCode(code);
        CompanyCodeInfo companyCodeInfo = companyCodeInfoMapper.selectOne(param);
        if (null == companyCodeInfo) {
            return;
        }
        Boolean update=Boolean.FALSE;
        CompanyStockMinutes companyStockMinutes = companyCodeInfoMapper.get60MaxTradeVol(code);
        if (companyStockMinutes != null) {
            BigDecimal maxTradeVol = companyStockMinutes.getTradeVol();
            if (maxTradeVol.compareTo(companyCodeInfo.getMaxDayVol60()) > 0) {
                log.info(">>>>>>>>>> name={}  update Max vol={} from New",companyStockMinutes.getCompanyName(),maxTradeVol);
                companyCodeInfo.setMaxDayVol60(maxTradeVol);
                update=Boolean.TRUE;
            }
        }
        CompanyStockMinutes companyStockMinutesHis = companyCodeInfoMapper.get60MaxTradeVolHis(code);
        if (companyStockMinutesHis != null) {
            BigDecimal maxTradeVol = companyStockMinutesHis.getTradeVol();
            if (maxTradeVol.compareTo(companyCodeInfo.getMaxDayVol60()) > 0) {
                log.info(">>>>>>>>>> name={}  update Max vol={}  from His",companyStockMinutes.getCompanyName(),maxTradeVol);
                companyCodeInfo.setMaxDayVol60(maxTradeVol);
                update=Boolean.TRUE;
            }
        }
        if(update){
            companyCodeInfoMapper.updateByPrimaryKey(companyCodeInfo);
        }
    }

    /**
     * 判断是否触发60天内预警
     */
    public void warnMax60Vol(CompanyStockMinutes companyStockMinutes) {
        try{
            BigDecimal maxDayVol60 = MAX_60_DAY_TRADE_VOL.get(companyStockMinutes.getCompanyCode());
            if (null == maxDayVol60) {
                CompanyCodeInfo param = new CompanyCodeInfo();
                param.setCompanyCode(companyStockMinutes.getCompanyCode());
                CompanyCodeInfo companyCodeInfo = companyCodeInfoMapper.selectOne(param);
                if (null == companyCodeInfo) {
                    return;
                }
                maxDayVol60 = companyCodeInfo.getMaxDayVol60();
                MAX_60_DAY_TRADE_VOL.put(companyStockMinutes.getCompanyCode(), maxDayVol60);
            }
            BigDecimal tradeVol = companyStockMinutes.getTradeVol();
            if (tradeVol.compareTo(maxDayVol60) >= 0&& companyStockMinutes.getZhangDie().compareTo(BigDecimal.ZERO) == 1) {
                String key = WARN_KEY + companyStockMinutes.getCompanyCode();
                if (null != redisUtil.get(key)) {
                    return;
                }
                MAX_60_DAY_TRADE_VOL.put(companyStockMinutes.getCompanyCode(), tradeVol);
                log.info(">>>>>>>>>> 触发60天量预警 code={} ,name={} vol={} ", companyStockMinutes.getCompanyCode(), companyStockMinutes.getCompanyName(), companyStockMinutes.getTradeVol());
                String reason = 获取涨停原因(companyStockMinutes);
                {
                    //查询涨停池
                    ZhangTingBan zhangTingBan = new ZhangTingBan();
                    zhangTingBan.setCode(companyStockMinutes.getCompanyCode());
                    zhangTingBanMapper.select(zhangTingBan);
                }

                String messages = new StringBuffer().append("触发60天量预警!!!涨幅：").append(companyStockMinutes.getZhangDie()).append("成交量：")
                        .append(tradeVol).append("【涨停原因：").append(StringUtils.isEmpty(reason) ? "未查询到" : reason).append("】").toString();
                EmailMessage emailMessage = new EmailMessage();
                emailMessage.setCode(companyStockMinutes.getCompanyCode());
                emailMessage.setName(companyStockMinutes.getCompanyName());
                emailMessage.setMessage(messages);
                emailMessage.setType("4");
                List<String> ids = Arrays.asList(commonService.getValue("WARN_MAX_VOL_ID").toString().split(","));
                for (String id : ids) {
                    User user = userMapper.selectByPrimaryKey(Long.valueOf(id));
                    emailMessage.setEmail(user.getEmail());
                    stockMsgSender.sendEmailMessage(JSONObject.toJSONString(emailMessage));
                }
                //跟新缓存
                {
                    asycTaskExecutorConfig.taskQueueExecutor().execute(() -> {
                        update预警信息();
                    });
                }
                redisUtil.set(key, companyStockMinutes.getCompanyCode(), 86400);
            }
        }catch (Exception exception){
            log.error(">>>>>>>>>>>> 判断是否触发60天内预警 error code={}",companyStockMinutes.getCompanyName());
        }
    }

    /**
     * 触发预警 更新缓存
     */
    public void update预警信息() {
        String key = StockWarningEvent_YU_JING + HolidayCopy.getRealToday();
        List<StockWarningEventEx> stockWarningEventExes = Lists.newArrayList();
        List<String> dates = companyStockMinutesMapper.queryDates();
        String date = dates.get(dates.size() - 2);
        StringBuffer datestr = new StringBuffer(date.substring(0, 4)).append("-").append(date.substring(4, 6)).append("-").append(date.substring(6, 8)).append(" 23:59:59");
        List<StockWarningEvent> stockWarningEventList = stockWarningEventMapper.yuJingList(datestr.toString());
        //去重
        List<StockWarningEvent> stockWarningEventListNew=Lists.newArrayList();
        List<String> nameList=Lists.newArrayList();
        for(StockWarningEvent stockWarningEvent:stockWarningEventList){
            if(!nameList.contains(stockWarningEvent.getName())){
                stockWarningEventListNew.add(stockWarningEvent);
                nameList.add(stockWarningEvent.getName());
            }
        }
        //data
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(stockWarningEventListNew)) {
            stockWarningEventListNew.stream().forEach(item -> {
                try {
                    查询预警信息(stockWarningEventExes, item);
                } catch (Exception e) {
                    log.error(">>>>>>>>> 查询预警信息:{}", e);
                }
            });
        }
        redisUtil.set(key, JSONObject.toJSONString(stockWarningEventExes));
        log.info(">>>>>>>>>>> update 预警信息");
    }

    private void 查询预警信息(List<StockWarningEventEx> stockWarningEventExes, StockWarningEvent item) {
        StockWarningEventEx stockWarningEventEx = new StockWarningEventEx();
        //查询公司
        CompanyCodeInfo param = new CompanyCodeInfo();
        param.setShortName(item.getName());
        CompanyCodeInfo companyCodeInfo = companyCodeInfoMapper.selectOne(param);
        stockWarningEventEx.setName(companyCodeInfo.getShortName());
        stockWarningEventEx.setMessage(item.getMessage());
        stockWarningEventEx.setWarnTime(HolidayCopy.getHHmmssByDate(item.getWarnTime()));
        if(StringUtils.isNotEmpty(companyCodeInfo.getTrendTypeName())){
            stockWarningEventEx.setWarnMessage(companyCodeInfo.getTrendTypeName());
        }else{
            stockWarningEventEx.setWarnMessage("-");
        }
        //查询minnutes
        CompanyStockMinutes companyStockMinutes = companyStockMinutesMapper.queryByCode(companyCodeInfo.getCompanyCode());
        if (null != companyStockMinutes) {
            stockWarningEventEx.setVol(companyStockMinutes.getTradeVol());
            stockWarningEventEx.setZhangDie(companyStockMinutes.getZhangDie());
            stockWarningEventEx.setCode(companyStockMinutes.getCompanyCode().replace("sh", "").replace("sz", ""));
        }else{
            stockWarningEventEx.setVol(BigDecimal.ZERO);
            stockWarningEventEx.setZhangDie(BigDecimal.ZERO);
            stockWarningEventEx.setCode("-");
        }
        //查询概念
        KaiPanLaZhangTingInfo kaiPanLaZhangTingInfo = kaiPanLaZhangTingInfoMapper.queyByCode(companyStockMinutes.getCompanyCode().replace("sh", "").replace("sz", ""));
        if (null != kaiPanLaZhangTingInfo) {
            stockWarningEventEx.setBk(kaiPanLaZhangTingInfo.getZyglbk());
            stockWarningEventEx.setZhangTingId(kaiPanLaZhangTingInfo.getId());
        }else{
            stockWarningEventEx.setBk("-");
            stockWarningEventEx.setZhangTingId(0L);
        }
        stockWarningEventExes.add(stockWarningEventEx);
    }

    private static String 获取涨停原因(CompanyStockMinutes companyStockMinutes) {
        String reason="";
        try {
            KaiPanLa kaiPanLa = MinutesChengJIaoeService.getGetDayZhangTing(companyStockMinutes.getCompanyCode().replace("sh", "").replace("sz", ""));
            log.info("读取第三方：code={}，result={}", companyStockMinutes.getCompanyCode(), JSONObject.toJSONString(kaiPanLa));
            List<KaiPanLaBaseInfo> list = kaiPanLa.getList();
            if (CollectionUtils.isNotEmpty(list)) {
                reason = list.get(0).getReason();
            }
        } catch (Exception e) {
        }
        return reason;
    }
}
